﻿using System;
using System.Collections.Generic;
using System.Data;
using DotNet.Configuration;
using DotNet.Doc;
using DotNet.Extensions;
using DotNet.Helper;
using System.Linq;
using System.Text;

namespace TimeCard.Core
{
    /// <summary>
    /// 服务对象
    /// </summary>
    public class ApiService
    {
        /// <summary>
        /// 用户规则服务
        /// </summary>
        public static readonly RuleService UserRuleService = new RuleService();

        /// <summary>
        /// 考勤数据模型对象
        /// </summary>
        public TimeCard Model { get; private set; }

        /// <summary>
        /// 考勤日期
        /// </summary>
        public DateTime ModelDate { get; private set; }

        /// <summary>
        /// 导入数据
        /// </summary>
        /// <param name="path">考勤原始数据</param>
        /// <param name="date">考勤日期</param>
        public void Import(string path, DateTime date)
        {
            ModelDate = date;
            Model = new TimeCard();
            Model.Year = date.Year;
            Model.Month = date.Month;

            //1.读取excel文件中的数据
            Model.UserRecordList = ExcelHelper.Import<UserRecord>(path, true);

            //2.获取获取本月天集合
            Model.DayList = GetDayList();

            //3.生成用户列表
            Model.UserList = GenerateUserList();

            //4.生成用户规则
            Model.UserRuleDic = GenerateUserRuleDic();
        }

        /// <summary>
        /// 查询考勤数据
        /// </summary>
        /// <param name="date">考勤日期</param>
        public void Search(DateTime date)
        {
            ModelDate = date;
            var dataPath = GetPath();
            Model = JsonHelper.Deserialize(dataPath, new TimeCard());
        }

        /// <summary>
        /// 保存考勤数据
        /// </summary>
        public void Save()
        {
            var dataPath = GetPath();
            JsonHelper.Serialize(dataPath, Model);
        }

        /// <summary>
        /// 获取数据文件路径
        /// </summary>
        /// <returns>返回数据文件路径</returns>
        private string GetPath()
        {
            return DirHelper.GetRootFilePath("Data", $"{ModelDate:yyyy-MM}.json");
        }

        /// <summary>
        /// 获取字典Key
        /// </summary>
        /// <param name="name">姓名</param>
        /// <param name="day">天(MM-dd)</param>
        public string GetDicKey(string name, string day)
        {
            return name + day;
        }

        /// <summary>
        /// 获取本月天集合,格式(MM-dd)
        /// </summary>
        private List<string> GetDayList()
        {
            var list = new List<string>();
            var day = DateTime.DaysInMonth(Model.Year, Model.Month);
            for (int i = 1; i <= day; i++)
            {
                var week = DateTimeHelper.GetWeekDay(new DateTime(Model.Year, Model.Month, i));
                list.Add($"{Model.Month:00}-{i:00}({week})");
            }
            return list;
        }

        /// <summary>
        /// 生成用户集合
        /// </summary>
        private List<User> GenerateUserList()
        {
            var list = new List<User>();
            var dic = new Dictionary<string, string>();
            foreach (var item in Model.UserRecordList)
            {
                dic[item.Name] = item.Dept;
            }
            foreach (var item in dic)
            {
                list.Add(new User(item.Key, item.Value));
            }
            return list;
        }

        /// <summary>
        /// 生成用户考勤规则集合
        /// </summary>
        private Dictionary<string, UserRule> GenerateUserRuleDic()
        {
            var dic = new Dictionary<string, UserRule>();

            foreach (var user in Model.UserList)
            {
                var rule = FindUserRule(user.Name);
                if (rule == null)
                {
                    continue;
                }
                foreach (var day in Model.DayList)
                {
                    if (!rule.HasWeekend && (day.IndexOf("星期六", StringComparison.Ordinal) > -1
                        || day.IndexOf("星期日", StringComparison.Ordinal) > -1))
                    {
                        continue;
                    }
                    var key = GetDicKey(user.Name, day);
                    dic.Add(key, rule);
                }
            }
            return dic;
        }

        private UserRule FindUserRule(string name)
        {
            foreach (var rule in UserRuleService.GetList())
            {
                if (!string.IsNullOrEmpty(rule.Users) && rule.Users.Split(',', '，').Any(p => p == name))
                {
                    return rule;
                }
            }
            return null;
        }

        /// <summary>
        /// 获取用户考勤规则表
        /// </summary>
        public DataTable GetUserRuleTable()
        {
            var table = new DataTable();
            table.Columns.Add("姓名");
            table.Columns.Add("部门");

            if (Model.DayList == null) return table;
            if (Model.UserList == null) return table;

            foreach (var day in Model.DayList)
            {
                table.Columns.Add(day);
            }

            foreach (var user in Model.UserList)
            {
                var row = table.NewRow();
                row["姓名"] = user.Name;
                row["部门"] = user.Dept;

                foreach (var day in Model.DayList)
                {
                    var key = GetDicKey(user.Name, day);
                    if (Model.UserRuleDic.ContainsKey(key))
                    {
                        row[day] = Model.UserRuleDic[key].ToString();
                    }
                }
                table.Rows.Add(row);
            }
            return table;
        }

        public void Submit()
        {
            Model.UserRecordDic = GenerateUserRecordDic();
            Model.UserResultDic = GenerateUserResultDic();
            Model.Report = GenerateReport();
        }

        private Dictionary<string, List<DateTime>> GenerateUserRecordDic()
        {
            var dic = new Dictionary<string, List<DateTime>>();

            foreach (var user in Model.UserList)
            {
                foreach (var days in Model.DayList)
                {
                    var key = GetDicKey(user.Name, days);
                    var day = days.Substring(3, 2).ToInt();
                    var dtList = Model.UserRecordList.
                        Where(p => p.Name == user.Name &&
                                   p.CardDateTime.Year == Model.Year &&
                                   p.CardDateTime.Month == Model.Month &&
                                   p.CardDateTime.Day == day).
                        Select(p => p.CardDateTime).
                        ToList();
                    if (dtList.Count > 0)
                    {
                        dic.Add(key, dtList);
                    }
                }
            }
            return dic;
        }

        private Dictionary<string, UserResult> GenerateUserResultDic()
        {
            var dic = new Dictionary<string, UserResult>();

            foreach (var user in Model.UserList)
            {
                foreach (var day in Model.DayList)
                {
                    var key = GetDicKey(user.Name, day);
                    if (!Model.UserRuleDic.ContainsKey(key)) //不没有规则,不添加 不考勤
                    {
                        continue;
                    }
                    var rule = Model.UserRuleDic[key];
                    var result = new UserResult();
                    result.Rule = rule;
                    if (Model.UserRecordDic.ContainsKey(key)) //如果有考勤记录
                    {
                        var kqList = Model.UserRecordDic[key];
                        var ruleStartTick = new TimeSpan(rule.StartHour, rule.StartMinute, 0).Ticks;
                        var ruleEndTick = new TimeSpan(rule.EndHour, rule.EndMinute, 0).Ticks;
                        var ruleCenterTick = ruleStartTick + (Math.Abs(ruleEndTick - ruleStartTick) / 2);
                        var kqTickList = kqList.Select(p => new TimeSpan(p.Hour, p.Minute, 0).Ticks).ToList();

                        var query = kqTickList.Where(p => p < ruleCenterTick).ToList();
                        if (query.Any())
                        {
                            var tick = query.Min();
                            var ts = new TimeSpan(tick);
                            result.StartHour = ts.Hours;
                            result.StartMinute = ts.Minutes;
                            kqTickList.Remove(tick);
                        }

                        query = kqTickList.Where(p => p > ruleCenterTick).ToList();
                        if (query.Any())
                        {
                            var tick = query.Max();
                            var ts = new TimeSpan(tick);
                            result.EndHour = ts.Hours;
                            result.EndMinute = ts.Minutes;
                            kqTickList.Remove(tick);
                        }
                    }
                    dic.Add(key, result);
                }
            }
            return dic;
        }

        public DataTable GetUserOriginalTable()
        {
            var table = new DataTable();
            table.Columns.Add("姓名");
            table.Columns.Add("部门");
            table.Columns.Add("打卡日期", typeof(DateTime));
            if (Model.UserRecordList == null) return table;
            foreach (var item in Model.UserRecordList)
            {
                var row = table.NewRow();
                row["姓名"] = item.Name;
                row["部门"] = item.Dept;
                row["打卡日期"] = item.CardDateTime;
                table.Rows.Add(row);
            }
            return table;
        }

        public DataTable GetUserResultTable()
        {
            var table = new DataTable();
            table.Columns.Add("姓名");
            table.Columns.Add("部门");
            if (Model.DayList == null) return table;
            if (Model.UserList == null) return table;
            if (Model.UserResultDic == null) return table;

            foreach (var day in Model.DayList)
            {
                table.Columns.Add(day);
            }

            foreach (var user in Model.UserList)
            {
                var row = table.NewRow();
                row["姓名"] = user.Name;
                row["部门"] = user.Dept;

                foreach (var day in Model.DayList)
                {
                    var key = GetDicKey(user.Name, day);
                    if (Model.UserResultDic.ContainsKey(key))
                    {
                        row[day] = Model.UserResultDic[key].ToString();
                    }
                    else
                    {
                        row[day] = "不考勤";
                    }
                }
                table.Rows.Add(row);
            }

            return table;
        }

        private string GenerateReport()
        {
            var reportList = new List<UserReport>();
            foreach (var user in Model.UserList)
            {
                var report = new UserReport();
                report.Name = user.Name;
                report.Dept = user.Dept;
                report.Details = new List<UserReportDetails>();
                reportList.Add(report);
                #region DayList
                foreach (var day in Model.DayList)
                {
                    var key = GetDicKey(user.Name, day);
                    if (!Model.UserResultDic.ContainsKey(key))
                    {
                        continue;
                    }
                    var d = day.Substring(3, 2).ToInt();
                    var result = Model.UserResultDic[key];
                    if (result.IsStartUnCard)
                    {
                        report.StartUnCard++;
                        var details = new UserReportDetails();
                        details.IsStartUnCard = true;
                        details.Result = result;
                        details.CardDate = new DateTime(Model.Year, Model.Month, d);
                        report.Details.Add(details);
                    }
                    else if (result.IsStartException)
                    {
                        report.StartException++;
                        var details = new UserReportDetails();
                        details.IsStartException = true;
                        details.Result = result;
                        details.CardDate = new DateTime(Model.Year, Model.Month, d);
                        report.Details.Add(details);
                    }
                    if (result.IsEndUnCard)
                    {
                        report.EndUnCard++;
                        var details = new UserReportDetails();
                        details.IsEndUnCard = true;
                        details.Result = result;
                        details.CardDate = new DateTime(Model.Year, Model.Month, d);
                        report.Details.Add(details);
                    }
                    else if (result.IsEndException)
                    {
                        report.EndException++;
                        var details = new UserReportDetails();
                        details.IsEndException = true;
                        details.Result = result;
                        details.CardDate = new DateTime(Model.Year, Model.Month, d);
                        report.Details.Add(details);
                    }
                }
                #endregion
            }

            var msg = new StringBuilder();
            foreach (var item in reportList)
            {
                var name = item.Name;
                if (name.Length == 2)
                {
                    name = "　" + name;
                }
                msg.Append($"{name}\t迟到:{item.StartException}次 " +
                           $"早退:{item.EndException}次 未打卡:{item.StartUnCard + item.EndUnCard}次\n");
                foreach (var d in item.Details)
                {
                    msg.Append($"\t\t{d.CardDate:MM-dd}  {d.Result}\n");
                }
                msg.Append("\r\n");
            }
            return msg.ToString();
        }
    }
}